#include "stdafx.h"
#include "SoundManager.h"
#include "Marco.h"

SoundManager* SoundManager::m_pThis = 0;

SoundManager::SoundManager()
{
	m_pDevice = alcOpenDevice(NULL);
	m_pContext = NULL;
	if (!m_pDevice)
	{
		printf("Error open AL Device!\n");
	}
	else
	{
		m_pContext = alcCreateContext(m_pDevice, 0);
		alcMakeContextCurrent(m_pContext);
		alGetError();
	}
	for (int i = 0; i < 10; i++)
	{
		listSound[i] = 0;
	}
}

void SoundManager::releaseSource(Sound sound)
{
	alDeleteBuffers(1, &sound.buffer);
	alDeleteSources(1, &sound.source);
}

SoundManager::~SoundManager()
{
	for (int i = 0; i < count; i++)
	{
		releaseSource(*listSound[i]);
		Delete(listSound[i]);
	}

}


// Get source id in return
Sound* SoundManager::Load(char* file_name)
{
	ALuint buffer_id, source_id;
	ALsizei freq, size;
	ALenum format;
	unsigned char* data;

	// load wav file

	if (!loadWavFile(file_name, data, &size, &freq, &format))
		return 0;


	// buffer the sound
	//create our openAL buffer and check for success
	alGenBuffers(1, &buffer_id);
	alGenSources(1, &source_id);
	//check for success
	if (alGetError() != AL_NO_ERROR)
	{
		printf("Error generating OpenAL buffer.\n");
		return 0;
	}

	alBufferData(buffer_id, format, (void*)data,
		size, freq);
	delete[] data;

	// bind the source
	alSourcei(source_id, AL_BUFFER, buffer_id);
	Sound* result = new Sound{ buffer_id, source_id };
	return result;
}
void SoundManager::Play(Sound sound, bool loop)
{
	alSourcei(sound.source, AL_LOOPING, loop);
	if (!isPlaying(sound))
		alSourcePlay(sound.source);
}


void SetPositionAttribute(Sound sound, Vector3 sound_position, Vector3 sound_velocity,
	Vector3 listener_position, Vector3 listener_velocity,
	Vector3 listener_orientation, Vector3 listener_up_vector
	)
{
	ALuint source = sound.source;
	// Position of the source sound.
	ALfloat SourcePos[] = { sound_position.x, sound_position.y, sound_position.z };

	// Velocity of the source sound.
	ALfloat SourceVel[] = { sound_velocity.x, sound_velocity.y, sound_velocity.z };

	// Position of the listener.
	ALfloat ListenerPos[] = { listener_position.x, listener_position.y, listener_position.z };

	// Velocity of the listener.
	ALfloat ListenerVel[] = { listener_velocity.x, listener_velocity.y, listener_velocity.z };

	// Orientation of the listener. (first 3 elements are "at", second 3 are "up")
	ALfloat ListenerOri[] = { listener_orientation.x, listener_orientation.y, listener_orientation.z,
		listener_up_vector.x, listener_up_vector.y, listener_up_vector.z };

	alListenerfv(AL_POSITION, ListenerPos);
	alListenerfv(AL_VELOCITY, ListenerVel);
	alListenerfv(AL_ORIENTATION, ListenerOri);
	alSourcef(source, AL_PITCH, 1.0f);
	alSourcef(source, AL_GAIN, 1.0f);
	alSourcefv(source, AL_POSITION, SourcePos);
	alSourcefv(source, AL_VELOCITY, SourceVel);
}


void SetSoundAttribute(Sound sound, ALfloat pitch, ALfloat gain)
{
	ALuint source = sound.source;
	alSourcef(source, AL_PITCH, pitch);
	alSourcef(source, AL_GAIN, gain);
}

void SoundManager::Pause(Sound sound)
{
	if (isPlaying(sound))
		alSourcePause(sound.source);
}
void SoundManager::Stop(Sound sound)
{
	if (isPlaying(sound))
		alSourceStop(sound.source);
}
bool SoundManager::isPlaying(Sound sound)
{
	ALenum sound_state;
	alGetSourcei(sound.source, AL_SOURCE_STATE, &sound_state);
	return (sound_state == AL_PLAYING);
}

bool loadWavFile(char* filename, unsigned char* &data, ALsizei* size, ALsizei* frequency, ALenum* format)
{

	//Local Declarations
	FILE* soundFile = NULL;
	WAVE_Format wave_format;
	RIFF_Header riff_header;
	WAVE_Data wave_data;
	soundFile = fopen(filename, "rb");
	if (!soundFile)
	{
		printf("ERROR loading Sound!\n");
		return false;
	}

	// Read in the first chunk into the struct
	fread(&riff_header, sizeof(RIFF_Header), 1, soundFile);

	//check for RIFF and WAVE tag in memeory
	if ((riff_header.chunkID[0] != 'R' ||
		riff_header.chunkID[1] != 'I' ||
		riff_header.chunkID[2] != 'F' ||
		riff_header.chunkID[3] != 'F') ||
		(riff_header.format[0] != 'W' ||
		riff_header.format[1] != 'A' ||
		riff_header.format[2] != 'V' ||
		riff_header.format[3] != 'E'))
		printf("Invalid RIFF or WAVE Header");

	//Read in the 2nd chunk for the wave info
	fread(&wave_format, sizeof(WAVE_Format), 1, soundFile);
	//check for fmt tag in memory
	if (wave_format.subChunkID[0] != 'f' ||
		wave_format.subChunkID[1] != 'm' ||
		wave_format.subChunkID[2] != 't' ||
		wave_format.subChunkID[3] != ' ')
		printf("Invalid Wave Format");

	//check for extra parameters;
	if (wave_format.subChunkSize > 16)
		fseek(soundFile, sizeof(short), SEEK_CUR);

	//Read in the the last byte of data before the sound file
	fread(&wave_data, sizeof(WAVE_Data), 1, soundFile);
	//check for data tag in memory
	if (wave_data.subChunkID[0] != 'd' ||
		wave_data.subChunkID[1] != 'a' ||
		wave_data.subChunkID[2] != 't' ||
		wave_data.subChunkID[3] != 'a')
		throw ("Invalid data header");

	//Allocate memory for data
	data = new unsigned char[wave_data.subChunk2Size];

	// Read in the sound data into the soundData variable
	if (!fread(data, wave_data.subChunk2Size, 1, soundFile))
		throw ("error loading WAVE data into struct!");

	//Now we set the variables that we passed in with the
	//data from the structs
	*size = wave_data.subChunk2Size;
	*frequency = wave_format.sampleRate;
	//The format is worked out by looking at the number of
	//channels and the bits per sample.
	if (wave_format.numChannels == 1) {
		if (wave_format.bitsPerSample == 8)
			*format = AL_FORMAT_MONO8;
		else if (wave_format.bitsPerSample == 16)
			*format = AL_FORMAT_MONO16;
	}
	else if (wave_format.numChannels == 2) {
		if (wave_format.bitsPerSample == 8)
			*format = AL_FORMAT_STEREO8;
		else if (wave_format.bitsPerSample == 16)
			*format = AL_FORMAT_STEREO16;
	}
	fclose(soundFile);
	return true;
}

int SoundManager::Load()
{
	int err = -1;
	Sound*temp = Load("..\\Sound\\test.wav");
	if (!temp)
		return err;
	listSound[count++] = temp;
}

void SoundManager::Play(int index)
{
	Play(*listSound[index], true);
}